#coding=utf8
from pyglet.gl import *
import pyglet
import squirtle
import svg_render
import copy

def sprite(image):
  return pyglet.sprite.Sprite(image,blend_src=GL_SRC_ALPHA, blend_dest=GL_ONE_MINUS_SRC_ALPHA)
  
def string_to_rgb(color):
  if color == 'white':
    return(255,255,255)
  elif color == 'black':
    return(0,0,0)
  if color == 'red':
    return(255,0,0)
  elif color == 'green':
    return(0,255,0)
  elif color == 'blue':
    return(0,0,255)
  elif color == 'yellow':
    return(255,0,255)
  elif color == 'purple':
    return(255,0,255)
  elif color == 'brown':
    return(255,120,120)
  elif color == 'orange':
    return(255,165,0)
  elif color == '':
    return(255,255,255)
      
class Channel:
  def __init__(self,name):
    self.name = name
    self.callbacks = []
  
    
  def set_block(self,acallback,block):
    for idx in range(len(self.callbacks)):
      if self.callbacks[idx][0] == acallback:
        self.callbacks[idx] = acallback,block
        return
    #print 'none is blocked'
        
  def transmit(self,*params):
    for callback in self.callbacks:
      if not callback[1]:
        if callback[0](*params):
          return True
        
class Transmitter:
  def __init__(self):
    self.blocked = False
    self._callbacks = []
    
  def __call__(self,*params):
    if not self.blocked:
      for callback in self.callbacks:
        if callback(*params):
          return True

class SignalInterface:
  def __init__(self):
    self.channels = {}
    
  def create_channel(self,channel):
    if channel not in self.channels:
      self.channels[channel] = Channel(channel)
    else:
      raise Exception('channel '+channel+' already exists')
    return self.channels[channel]
  
  def set_block(self,channel,callback,block):
    if channel not in self.channels:
      raise Exception('channel '+channel+' doesnt exist')
    self.channels[channel].set_block(callback,block)
    
  def get_channel(self,channel):
    if channel not in self.channels:
      raise Exception('channel '+channel+' doesnt exist')
    return self.channels[channel]
      
  def connect_to_channel(self,channel,callback,blocked = False):
    if channel not in self.channels:
      raise Exception('channel '+channel+' doesnt exist')
    self.channels[channel].callbacks.append((callback,blocked))
  
  
      
  
  def transmit_to_channel(self,channels):
    if channel not in self.channels:
      self.channels[channel] = Channel(channel)
    


common_signals = SignalInterface()

class Skin:
    def __init__(self):
      self.render = svg_render.SVG_Render()
      self.atlas = []
      self.atlas.append(pyglet.image.atlas.TextureAtlas(1024,1024))
      self.current_atlas = self.atlas[-1]
      self.regions = {}
      
    def ref(self,name,width,height):
      if not self.render.isLoaded(name,width,height):
        try:
          self.regions[name,width,height] = self.current_atlas.add(self.render.getImage(name,width,height))
        except:
          try:
            self.atlas.append(pyglet.image.atlas.TextureAtlas(1024,1024))
            self.current_atlas = self.atlas[-1]
            self.regions[name,width,height] = self.current_atlas.add(self.render.getImage(name,width,height))
          except :
            raise Exception('The image '+name+' is too big '+str(width)+','+str(height))
      return sprite(self.regions[name,width,height])

default_skin = Skin()

class Signal:
  def __init__(self,window):
    self.window = window
    self.on_mouse_events_layouts = []
    self.on_key_events_layouts = []
    self.on_text_layouts = []
    
    self.mouse_press = common_signals.create_channel('events/mouse/mouse_press')
    self.mouse_release = common_signals.create_channel('events/mouse/mouse_release')
    self.mouse_scroll = common_signals.create_channel('events/mouse/mouse_scroll')
    self.mouse_drag = common_signals.create_channel('events/mouse/mouse_drag')
    self.mouse_motion = common_signals.create_channel('events/mouse/mouse_motion')
    
    self.key_press = common_signals.create_channel('events/key/key_press')
    self.key_release = common_signals.create_channel('events/key/key_release')
    self.text = common_signals.create_channel('events/text/text')
    self.text_motion = common_signals.create_channel('events/text/text_motion')
    self.text_motion_select = common_signals.create_channel('events/text/text_motion_select')
    
    
    @self.window.event
    def on_mouse_press(x,y,button,mod):
      self.mouse_press.transmit(x,y,button,mod)
      
    def on_mouse_scroll(x,y,dx,dy):
      self.mouse_scroll.transmit(x,y,dx,dy)
      
    @self.window.event
    def on_mouse_release(x,y,button,mod):
      self.mouse_release.transmit(x,y,button,mod)
    
    @self.window.event
    def on_mouse_motion(x,y,dx,dy):
      self.mouse_motion.transmit(x,y,dx,dy)
      
    @self.window.event
    def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
      self.mouse_drag.transmit(x,y,dx,dy,buttons,modifiers)
    
    @self.window.event
    def on_key_press(key,modifiers):
      self.key_press.transmit(key,modifiers)
        
    @self.window.event
    def on_key_release(key,modifiers):
      self.key_release.transmit(key,modifiers)
        
    @self.window.event
    def on_text_motion_select(text):
      self.text_motion_select.transmit(text)
      
      
    @self.window.event
    def on_text_motion(text):
      self.text_motion.transmit(text)
      
    @self.window.event
    def on_text(text):
      self.text.transmit(text)
    
    
    @window.event
    def on_mouse_scroll(x, y, scroll_x, scroll_y):
      self.mouse_scroll.transmit(x,y,scroll_x,scroll_y)
      

class LayeredRender:
  def __init__(self,layer_count):
    self.layer_count = 8
    self.batch = pyglet.graphics.Batch()
    self.text_batch_front = pyglet.graphics.Batch()
    self.text_batch_back = pyglet.graphics.Batch()
    
    self.back_layers = []
    self.front_layers = []
    for idx in range(layer_count):
     self.back_layers.append(pyglet.graphics.OrderedGroup(idx))
     self.front_layers.append(pyglet.graphics.OrderedGroup(idx))
     
    self.elements = []
    
  #We should place non-animated and non-SVG elements into batch
  def widget_to_front(self,widget):
    for layers,counter in zip(widget.get_ordered_elements(),range(self.layer_count)):
      for element in layers:
        if element.__class__.__name__ not in ('SVG','IncrementalTextLayout','HListBox','IncrementalTextLayout','Layout','CentralLayout','GridLayout','ScrollableLayout','Button','PictureButton','Bar','Combobox','Scroller','VScroller','Frame'):
            element.group = self.front_layers[counter]
  
  def widget_to_back(self,widget):
    for layers,counter in zip(widget.get_ordered_elements(),range(self.layer_count)):
      for element in layers:
        if element.__class__.__name__ not in ('SVG','IncrementalTextLayout','HListBox','IncrementalTextLayout','Layout','CentralLayout','GridLayout','ScrollableLayout','Button','PictureButton','Bar','Combobox','Scroller','VScroller','Frame'):
          element.group = self.back_layers[counter]
        
  def add_widget(self,widget):
    widget.update_rect()
    for layers,counter in zip(widget.get_ordered_elements(),range(self.layer_count)):
      for element in layers:
        if element.__class__.__name__ in ('SVG','IncrementalTextLayout','IncrementalTextLayout','HListBox','Layout','CentralLayout','GridLayout'):
          self.elements.append(element)
        elif element.__class__.__name__ in ('Label'):
          element.set_batch(self.batch)
          element.group = self.back_layers[counter]
      
        elif element.__class__.__name__ in ('ScrollableLayout','Button','PictureButton','Bar','Combobox','Scroller','VScroller','Frame'):
          pass
        else:
          element.batch = self.batch
          element.group = self.back_layers[counter]
  
  def draw(self):
    self.batch.draw()
    for element in self.elements:
      element.draw()


def hit_rect(x,y,rect):
  
  if x < rect[0]:
    return False
  
  if x > rect[2]:
    return False
  
  if y < rect[1]:
    return False    
  if y > rect[3]:
    return False
    
  return True
  
class Widget(object):
  def __init__(self,pos = (0,0),size = (64,32)):
    self.name = ''
    self.active = True
    self.x = pos[0]
    self.y = pos[1]
    self.tip_caption = None
    self.width = size[0]
    self.height = size[1]
    self.draggable = False
    self._visible = True
    self.ignore_in_layout = False
    self.parent = None

  def get_position(self):
    stx,sty=0,0
    if self.parent is not None:
      stx,sty = self.parent.get_position()
      if self.parent.__class__.__name__ == 'CentralLayout':
        stx += self.parent.internal_scroll_x
        sty += self.parent.internal_scroll_y
    return self.x+stx,self.y+sty
  
  def _get_visible(self):
    return self._visible
    
  def _set_visible(self, value):
    self._visible = value
    #self.update_rect()
    for layers in self.get_ordered_elements():
      for element in layers:
        if element is not self:
          element.visible = value
    
  visible = property(fget = _get_visible, fset = _set_visible)
  
  def update_rect(self):
    pass
    
  def hit_test(self,x,y):
    
    px,py = self.get_position()
      
    if x < px:
      return False
    if y < py:
      return False
    if x > px+self.width:
      return False
    if y > py+self.height:
      return False
    return True
    
  def listens(self):
    return []
  
  def get_ordered_elements(self):
    return []
  
  def draw(self):
    raise Exception("Widget cannot draw itself")
    
    
  def focus(self):
    pass
    
  def unfocus(self):
    pass


class Shortcut:
  def __init__(self):
    pass
  def listen_events(self):
    pass

def set_clip_rect(rect):
  glPushAttrib(GL_ENABLE_BIT | GL_TRANSFORM_BIT | GL_CURRENT_BIT)
  glEnable(GL_BLEND)
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  # Disable clipping planes to check culling.
  glEnable(GL_CLIP_PLANE0)
  glEnable(GL_CLIP_PLANE1)
  glEnable(GL_CLIP_PLANE2)
  glEnable(GL_CLIP_PLANE3)
  # Left
  glClipPlane(GL_CLIP_PLANE0, (GLdouble * 4)(
              1, 0, 0, -(rect[0])))
  # Top
  glClipPlane(GL_CLIP_PLANE1, (GLdouble * 4)(
              0, -1, 0, rect[3] ))
  # Right
  glClipPlane(GL_CLIP_PLANE2, (GLdouble * 4)(
              -1, 0, 0, rect[2] + 1))
  # Bottom
  glClipPlane(GL_CLIP_PLANE3, (GLdouble * 4)(
                0, 1, 0, -(rect[1])))

def unset_clip_rect():
  glPopAttrib()
                
class Layout(Widget,object):
  def __init__(self,asize=(1024,768)):
  
    Widget.__init__(self,size=asize)
    self.focused_widget= None
    self.widgets = []
    self.shortcuts = []
    self.layered_render = LayeredRender(5)
    self.active = True
    self.internal_scroll_x = 0
    self.internal_scroll_y = 0
    
    self.state = 'idle'
    self.transmitters = {}
    self.widget_names = ('ScrollableLayout','Button','HListBox','Bar','Combobox','Scroller','VScroller','CentralLayout','Layout','GridLayout','PictureButton')
    common_signals.connect_to_channel("events/mouse/mouse_press",self.mouse_press)
    common_signals.connect_to_channel("events/mouse/mouse_release",self.mouse_release)
  
  def get_ordered_elements(self):
    return []
  
  def _get_visible(self):
    
    return self._visible
    
  def _set_visible(self, value):
    for element in self.widgets:
      element.visible = value
    self.unfocus()
    #self.update_rect()
    
  visible = property(fget = _get_visible, fset = _set_visible)
  
  def bring_to_front(self,widget):
    self.widgets.remove(widget)
    self.widgets.insert(0,widget)
    self.layered_render.widget_to_front(widget)
    for element in widget.get_ordered_elements():
      if element.__class__.__name__ in self.widget_names:
        self.bring_to_front(element)
    widget.focus()
  def hit_test(self,x,y):
    for widget in self.widgets:
      if widget.hit_test(x,y) and widget.visible:
        return True
    return False
  def focus_widget(self,widget):
    self.unfocus()
    self.focused_widget = widget
    for ch in widget.listens():
      if ch[0] not in self.transmitters:
        self.transmitters[ch[0]] = Transmitter()
        common_signals.get_channel(ch[0]).callbacks.append((self.transmitters[ch[0]],False))
      self.transmitters[ch[0]].callbacks = [ch[1]]
      self.bring_to_front(widget)
      widget.focus()
      
  def unfocus(self):
    if self.focused_widget is not None:
      self.focused_widget.unfocus()
      self.layered_render.widget_to_back(self.focused_widget)
          
    self.focused_widget = None
    for t in self.transmitters:
      self.transmitters[t].callbacks = []
      
  def add_widget(self,widget):
    for layer in widget.get_ordered_elements():
      for el in layer:
        if el.__class__.__name__ in self.widget_names:
          #el.ignore_in_layout = True
          el.parent = self
          if el!=widget:
            self.add_widget(el)
        
    widget.parent = self
    self.widgets.append(widget)
    self.layered_render.add_widget(widget)
  
  def remove_widget(self,widget):
    for el in widget.get_ordered_elements():
      self.remove_widget(el)
    self.widgets.erase(widget)
    self.layered_render.remove_widget(widget)
    
  def mouse_press(self,x,y,button,mod):
    if self.focused_widget is not None and self.focused_widget.hit_test(x,y):
      return
    if self.visible:
      if not self.hit_test(x,y):
        self.unfocus()
        
      if self.state == 'idle':
        self.unfocus()
        self.state == 'pressed' 
        for wg in self.widgets:
          if wg.hit_test(x,y) and wg.visible:
            self.focus_widget(wg)
            
  def mouse_release(self,x,y,button,mod):
    self.state = 'idle'
    
  def draw(self):
    glPushMatrix()
    if self.visible:
      self.set_clipping()
      glTranslatef(self.x,self.y,0)
      glTranslatef(self.internal_scroll_x,self.internal_scroll_y,0)
      self.layered_render.draw()
      self.unset_clipping()
    glPopMatrix()
  
  
  def listens(self):
    return [('events/mouse/mouse_press',self.mouse_press),('events/mouse/mouse_release',self.mouse_release)]
    
  def set_clipping(self):
    set_clip_rect((self.x,self.y,self.x+self.width,self.y+self.height*2))
  
  def unset_clipping(self):
    unset_clip_rect()
  
  def update_rect(self):
    for widget in self.widgets:
      widget.update_rect()
      
class CentralLayout(Layout):
  def __init__(self,size,spacing  = 5.0,max_size_align = False):
    Layout.__init__(self)
    self.x = 0
    self.y = 0
    
    self.width = size[0]
    self.height = size[1]
    
    self.max_size_align = True
    self.spacing = spacing
    
  #getting the elements 
  def update_rect(self):
    all_widget_size = 0
    max_size = 0
    for widget in self.widgets:
      if not widget.ignore_in_layout:
        all_widget_size += widget.height+self.spacing
        if widget.width > max_size:
          max_size = widget.width
    
    pos = (self.height - all_widget_size)/2
    pos = self.height - pos
    for widget in self.widgets:
      if not widget.ignore_in_layout:
        if self.max_size_align and (widget.width,widget.height) == (0,0):
          widget.size = max_size,widget.height
        pos  -= widget.height+self.spacing
        
        x = (self.width)/2.0 - widget.width/2.0
        y = pos
        widget.x = x 
        widget.y = y
        
        widget.update_rect()
      
class GridLayout(Layout):
  def __init__(self,size,tsize = (9,9),step = (0,0)):
    Layout.__init__(self)
    
    self.x = 0
    self.y = 0
    
    self.step = step
    self.tsize = tsize
    self.width = size[0]
    self.height = size[1]
    
    
  def update_rect(self):
    counter = 0
    if self.step == (0,0):
      self.step = self.width/self.tsize[0],self.height/self.tsize[1]
    counter=0
    for widget in self.widgets:
      x =  5 + self.step[0] * int(counter%self.tsize[0])  
      y = self.height - self.step[1] -self.step[1] * int(counter/self.tsize[1])
      widget.x = x
      widget.y = y
      counter+=1
      widget.update_rect()
    
      
class Bar(Widget):
  def __init__(self,name,caption = '',pos = (0,0),size = (0,0),skin = default_skin,on_drag = None):
    Widget.__init__(self,pos,size)
    #custom params
    self._caption = caption
    self.state = 'idle'
    self.name = name
    #custom visuals
    self.caption_visual = pyglet.text.Label(caption, font_name='Arial', halign = "center",  color = (0,0,0,255), font_size=11,dpi=80, x=0, y=0)

    if size == (0,0):
      self.width = self.caption_visual.content_width + 10
      self.height = self.caption_visual.content_height+5
    
    self.svg = skin.ref('graphics/bar.svg',self.width,self.height)
    
    self.caption_spacev = (self.width - self.caption_visual.content_width)/2
    self.caption_spaceh = (self.height - self.caption_visual.content_height)/2
    
    self.update_rect()
    self.on_drag = common_signals.create_channel("gui_events/on_drag/"+self.name)
  
  def _set_caption(self,value):
    if self._caption == value:
      return
    self._caption = value
    self.caption_visual.text = self._caption
    self.update_rect()
  
  def _get_caption(self):
    return self._caption
  
  caption = property (_get_caption,_set_caption)
  def get_ordered_elements(self):
    return [[self.svg],[self.caption_visual]]
    
  def update_rect(self):
    self.svg.x = self.x
    self.svg.y = self.y
    
    self.caption_spacev = (self.width - self.caption_visual.content_width)/2
    self.caption_spaceh = (self.height - self.caption_visual.content_height)/2
    
    self.caption_visual.x = self.x + self.caption_spacev
    self.caption_visual.y = self.y + self.caption_spaceh
   
    
  def mouse_drag(self,x, y, dx, dy, buttons, modifiers):
    #if self.hit_test(x,y):
    self.x +=dx
    self.y +=dy
    self.on_drag.transmit(x,y,dx,dy,buttons,modifiers)
    self.update_rect()
  
  def listens(self):
    return [('events/mouse/mouse_drag',self.mouse_drag)]

class Frame(Widget):
  def __init__(self,name,caption = '',pos = (0,0),size = (100,100),skin = default_skin,layout = None):
    Widget.__init__(self,pos,size)
    #common_signals.connect_to_channel("events/mouse/mouse_drag",self.bar.mouse_drag)
    self.svg = skin.ref('graphics/frame.svg',self.width,self.height)
    self.bar = Bar(name+"_bar",caption,size = (self.width,20))
    self.layout = layout
    if self.layout is None:
      self.layout = GridLayout(size)
    self.update_rect()
    common_signals.connect_to_channel("gui_events/on_drag/"+name+"_bar",self.on_drag)
    
  def get_ordered_elements(self):
    return [[self.svg],[self.bar],[self.layout]] 
  
  def on_drag(self,x,y,dx,dy,buttons,modifiers):
    self.x +=dx
    self.y +=dy    
    self.svg.x = self.x
    self.svg.y = self.y
    
    self.bar.x = self.x
    self.bar.y = self.y + self.height 
    
    self.layout.x = self.x
    self.layout.y = self.y
  
    
  def update_rect(self):
    self.svg.x = self.x
    self.svg.y = self.y
    
    self.bar.x = self.x
    self.bar.y = self.y + self.height 
    self.bar.update_rect()
    
    self.layout.x = self.x
    self.layout.y = self.y
    self.layout.update_rect()
    
   
    
class Button(Widget):
  def __init__(self,name,caption = '',pos = (0,0),size = (0,0),skin = default_skin):
    Widget.__init__(self,pos,size)
    self._caption = caption
    self.state = 'idle'
    self.name = name
    #custom visuals
    self.caption_visual = pyglet.text.Label(caption, font_name='Arial', halign = "center", color = (0,0,0,255), font_size=11,dpi=80, x=0, y=0)
    
    if size == (0,0):
      self.width = self.caption_visual.content_width + 10
      self.height = self.caption_visual.content_height+5
      
    self.svg = skin.ref('graphics/button.svg',self.width,self.height)
    
    self.caption_spacev = (self.width - self.caption_visual.content_width)/2
    self.caption_spaceh = (self.height - self.caption_visual.content_height)/2+3
    self.on_click = common_signals.create_channel("gui_events/on_click/"+self.name)
    
    self.update_rect()
   
  def _set_caption(self,value):
    if self._caption == value:
      return
    self._caption = value
    self.caption_visual.text = self._caption
  
  def _get_caption(self):
    return self._caption
  
  caption = property (_get_caption,_set_caption)
  
  def get_ordered_elements(self):
    return [[self.svg],[self.caption_visual]]
  
  def listens(self):
    return [('events/mouse/mouse_press',self.mouse_press),('events/mouse/mouse_release',self.mouse_release)]
    
  def update_rect(self):
    self.svg.x = self.x
    self.svg.y = self.y
    self.caption_visual.x = self.x + self.caption_spacev
    self.caption_visual.y = self.y + self.caption_spaceh
    #~ self.scale = ()
    #~ self.svg.scale = (float(self.width)/self.svg.width,float(self.height)/self.svg.height)
    
  def mouse_press(self,x,y,button,mod):
    if self.hit_test(x,y) and self.visible:
      self.state = 'down' 
      self.svg.y = self.y - 2
      self.caption_visual.y = self.y + self.caption_spaceh - 2
      #return True
    return False
    
  def mouse_release(self,x,y,button,mod):
      if self.state == 'down' and self.visible: 
        self.svg.y = self.y
        self.caption_visual.y = self.y + self.caption_spaceh
        self.on_click.transmit(self)
        #return True
      

class PictureButton(Widget):
  def __init__(self,name,image,pos = (0,0),size = (0,0),skin = default_skin):
    Widget.__init__(self,pos,size)
    self.state = 'idle'
    self.name = name
    #custom visuals
    self._image = sprite(image)
    if size == (0,0):
      self.width = 40
      self.height = 40
    
    self.svg = skin.ref('graphics/button.svg',self.width,self.height)
    
    self.image_spacev = 0
    self.image_spaceh = 0
    self.update_rect()
    self.on_click = common_signals.create_channel("gui_events/on_click/"+self.name)
    
    
  def get_ordered_elements(self):
    return [[self.svg],[self.image]]
  
  def listens(self):
    return [('events/mouse/mouse_press',self.mouse_press),('events/mouse/mouse_release',self.mouse_release)]
  
  def _set_image(self,image):
    self._image.image = image
  
  def _get_image(self):
    return self._image
  
  image = property(_get_image,_set_image)
  
  def update_rect(self):
    self.svg.x = self.x
    self.svg.y = self.y
    #~ self.svg.draw(self.scale)
    self._image.x = self.x 
    self._image.y = self.y 
    self._image.scale = float(self.width) / self._image.image.width,float(self.height)/self._image.image.height
    
    self.scale = ()
  
    
  def mouse_press(self,x,y,button,mod):
    if self.hit_test(x,y):
      self.state = 'down' 
      self.svg.y = self.y - 2
      self.image.y = self.y - 2
  
  def mouse_release(self,x,y,button,mod):
      if self.state == 'down': 
        self.svg.y = self.y
        self.image.y = self.y + self.image_spaceh
        self.on_click.transmit(self)

class Scroller(Widget):
  def __init__(self,name,pos = (0,0),size = (0,0),length = 100,skin = default_skin,horizontal = True):
    Widget.__init__(self,pos,size)
    self.slider= skin.ref('graphics/slider.svg',20,20)
    self.slider_field= skin.ref('graphics/slider_field.svg',self.width,20)
    self.value = 0
    self.name = name
    self.length = length
    self.on_value_changed = common_signals.create_channel("gui_events/on_value_changed/"+self.name)
    self.coeff = (float(self.width)/float(self.length))
    
  def bound(self):
    if self.value > self.length:
      self.value = self.length
    if self.value < 0:
      self.value = 0
    self.on_value_changed.transmit(self.value)
      
  def on_drag(self,x, y, dx, dy, buttons, modifiers):
    self.value+=int(round(float(dx)/self.coeff))
    self.bound()
    self.update_rect()
  def on_scroll(self,x,y,sc_x,sc_y):
    self.value+=sc_y
    self.bound()
    self.update_rect()
    
  def get_ordered_elements(self):
    return [[self.slider_field],[self.slider]]
  
  def listens(self):
    return [('events/mouse/mouse_scroll',self.on_scroll),('events/mouse/mouse_drag',self.on_drag)]
  
  def update_rect(self):
    self.slider.x = self.x+self.coeff*float(self.value) -self.slider.width/2
    self.slider.y = self.y
    
    self.slider_field.x = self.x
    self.slider_field.y = self.y

class VScroller(Scroller):
  def __init__(self,name,pos = (0,0),size = (0,0),length=100,skin = default_skin,horizontal = True):
    Scroller.__init__(self,name,pos,size,length,skin)
    self.slider_field= skin.ref('graphics/slider_field.svg',self.height,20)
    
  def on_drag(self,x, y, dx, dy, buttons, modifiers):
    self.value+=int(round(float(dy)/self.coeff))
    self.bound()
    self.coeff = (float(self.height)/float(self.length))
    self.update_rect()
    
  def update_rect(self):
    self.slider.x = self.x
    self.slider.y = self.y+self.coeff*float(self.value) - self.slider.height/2
    self.slider_field.rotation = -90
    self.slider_field.x = self.x+self.slider.width
    self.slider_field.y = self.y
    #fself.slider_field.scale = (float(self.height)/self.slider_field.height,float(self.width)/self.slider_field.width)


class ScrollableLayout(Widget):
  def __init__(self,name,pos,size,viewsize,layout,skin = default_skin):
    Widget.__init__(self,pos,size)
    self.name = name
    self.field_width = viewsize[0]
    self.field_height = viewsize[1]
    self.svg = skin.ref('graphics/frame.svg',self.width,self.height)
    self.layout = layout
    self.scroller = Scroller(name+'_hscroll',pos,size =(self.width,20),length = 100)
    self.vscroller = VScroller(name+'_vscroll',pos,size =(20,self.height),length = 100)
    common_signals.connect_to_channel('gui_events/on_value_changed/'+name+'_vscroll',self.vscroll)
    common_signals.connect_to_channel('gui_events/on_value_changed/'+name+'_hscroll',self.hscroll)
    self.layout.internal_scroll_y = self.height*2
    self.layout.parent = self
    self.visible = False
    self.update_rect()
  
  def hscroll(self,val):
    self.layout.internal_scroll_x = self.height - val
    
  def vscroll(self,val):
    self.layout.internal_scroll_y = self.height*2 - val
    
  def update_rect(self):
    if not self.field_width > self.width:
      self.scroller.visible = False
      
    if not self.field_height > self.height:
      self.vscroller.visible = False
      
    self.scroller.x = self.x 
    self.scroller.y = self.y + self.height
    self.scroller.update_rect()
      
    self.vscroller.x = self.x + self.width
    self.vscroller.y = self.y
    self.vscroller.update_rect()
    
    self.svg.x = self.x
    self.svg.y = self.y
    
    self.layout.x = self.x    
    self.layout.y = self.y
  

  def get_ordered_elements(self):
    return [[self.svg,self.scroller,self.vscroller],[self.layout]]
    
    
class Combobox(Widget):
  def __init__(self,name,values,pos=(0,0),size=(120,20),skin = default_skin):
    Widget.__init__(self,pos,size = (120,20))
    if len(values) < 1:
      raise ('You don\'t need empty combobox')
    self.current_value = values[0]
    self.total_size = len(values)*20+20
    self.button = skin.ref('graphics/button.svg',self.width,self.height)
    self.field = skin.ref('graphics/list.svg',self.width,self.total_size)
    self.field.visible = False
    
    self.name = name
    self.current_value_label = pyglet.text.Label(self.current_value, font_name='Arial', halign = "center", color = (0,0,0,255), font_size=11,dpi=80, x=0, y=0)
    self.current_value_label.width,self.current_value_label.height = 120,20
    self.current_value_label.anchor_x,self.current_value_label.anchor_y = 'center','center'
    self.values = values
    self.value_labels = []
    for value in self.values:
      self.value_labels.append(pyglet.text.Label(value, font_name='Arial', halign = "center", color = (0,0,0,255), font_size=11,dpi=80, x=0, y=0))
      self.value_labels[-1].width,self.current_value_label.height = 120,20
      self.value_labels[-1].anchor_x,self.current_value_label.anchor_y = 'center','center'
      self.value_labels[-1].visible = False
    
    self.value_changed = common_signals.create_channel('gui_events/value_changed/'+self.name)
    
  def click(self,sender):
    self.button.caption = sender.caption
    #~ self.update_rect()
    self.scrollable.visible = False
    self.current_value
    #self.height = 20
  
  
  def on_press(self,x,y,button,mod):
    
    pos = self.get_position()
    x,y,(pos[0],pos[1],pos[0]+self.width,pos[1]+self.total_size)
    
    if hit_rect(x,y,(pos[0],pos[1]+20,pos[0]+self.width,pos[1]+self.height)):
     
      self.current_value = self.values[int((y - (pos[1]+20))/20)]
      self.field.visible = False 
      self.height = 20
      self.current_value_label.text = self.current_value
      self.value_changed.transmit(self.current_value)
      for value in self.value_labels:
        value.visible = False
      return True
      
    self.field.visible = True
    self.height = self.total_size
    for value in self.value_labels:
      value.visible = True
    
  def unfocus(self):
    self.field.visible = False
    for value in self.value_labels:
      value.visible = False
    self.height = 20
  def open(self,sender):
    if not self.scrollable.visible:
      self.scrollable.visible = True
      #self.height = 100
    else:
      self.scrollable.visible = False
      #self.height = 20
      
  def get_ordered_elements(self):
    return [[self.button],[self.current_value_label],[self.field],self.value_labels]
    
  def update_rect(self):
    self.button.x = self.x
    self.button.y = self.y
    self.current_value_label.x,self.current_value_label.y = self.x+60,self.y+10
    self.field.x,self.field.y=self.x,self.y+20
    counter = 0
    for label in self.value_labels:
      label.x = self.x + 60
      label.y = self.y + 30 + counter*20
      counter+=1
   
  
  def _get_visible(self):
    return self._visible
    
  def _set_visible(self, value):
    self._visible = value
    #~ for element in self.get_ordered_elements():
      #~ element.visible = False
    
  visible = property(fget = _get_visible, fset = _set_visible)
  
  def listens(self):
    return [('events/mouse/mouse_press',self.on_press)]
  

class TextLabel(Widget):
  pass
  
class Picture(Widget):
  pass

class HListBox(Widget):
  def __init__(self,name,elements,pos = (0,0),size=(120,30),multiselect = False,noselect = False,skin = default_skin):
    Widget.__init__(self,pos,size)
    self.name = name
    self.sprites = []
    self.batch = pyglet.graphics.Batch()
    self.element_size = float(self.height - 4)
    self.spacing = 0
    self.max_scroll = len(self.sprites)*(self.element_size+self.spacing) - self.width
    self._scroll = 0
    self.field = skin.ref('graphics/list.svg',self.width,self.height)
    self.a_right = skin.ref('graphics/arrow.svg',10,self.height)
    self.a_left = skin.ref('graphics/arrow.svg',10,self.height)
    self.a_left.rotation = 180
    self.state = 'idle'
    self.update_rect()
    self.selection = []
    self.noselect = noselect
    self.multiselect = multiselect
    self.elements = []
    self.on_selection_changed = common_signals.create_channel("gui_events/on_selection_changed/"+self.name)
    self.set_elements(elements)
  
  def set_elements(self,elements):
    
    self.clear()
    self._scroll = 0
    self.elements = elements
    self.selection = []
    if not len(elements) > 0: return
    for element in elements:
      tmp = sprite(element)
      tmp.scale = (self.element_size/element.width),(self.element_size/element.height)
      tmp.x,tmp.y = len(self.sprites)*(self.element_size+self.spacing),self.spacing
      tmp.batch = self.batch
      tmp.opacity = 60
      self.sprites.append(tmp)
    
  
    self.max_scroll = len(self.sprites)*(self.element_size+self.spacing) - self.width - 30
    print self.max_scroll
    self.update_rect()
    if self.noselect:
      self.clear_selection()
    else:
      self.set_selection(0)
    
  def clear(self):
    for sprite in self.sprites:
      del sprite
    self.elements = []
    self.selection = []
    self.sprites = []
    self.max_scroll = 0
    self._scroll = 0
    
  def update_rect(self):
    self.field.x = self.x
    self.field.y = self.y
    self.a_left.x = self.width
    self.a_left.y = self.height
  
  def on_release(self,x,y,buttons,modifier):
    self.state = 'idle'
    return False
  
  def clear_selection(self):
    if len(self.selection)>0:
      for element in self.selection:
        self.sprites[element].opacity = 60
    self.selection = []
    
  def select_all(self):
    self.clear_selection()
    for i in range(len(self.elements)):
      self.set_selection(i)
      
  def set_selection(self,index):
 
    if index >= len(self.sprites): return
    if self.multiselect:
      if index not in self.selection:
        self.sprites[index].opacity = 255
        self.selection.append(index)
      else:
        self.selection.remove(index)
        self.sprites[index].opacity = 60
        
    else:
      if len(self.selection)==0: 
        self.sprites[index].opacity = 255
        self.selection = [index]
      else:
        if self.noselect and self.selection[0] == index:
          self.sprites[self.selection[0]].opacity = 60
          self.selection = []
        else:
          self.sprites[self.selection[0]].opacity = 60
          self.sprites[index].opacity = 255
          self.selection = [index]
        
    self.on_selection_changed.transmit(self.selection)
  
  def on_press(self,x,y,buttons,modifier):
    x,y =  x - self.get_position()[0],y-self.get_position()[1]
    if x < 10:
      self.state = 'scroll_right'
    elif x > self.width - 10:
      self.state = 'scroll_left'
    else:
      x = x - self.element_size/2
      self.set_selection(int((x+self._scroll)/(self.element_size+self.spacing)))
    return True
  
  def get_ordered_elements(self):
    return [[self]]
  
  def scroll(self,val):
    if self._scroll+val < 0:
      return
    if self._scroll+val >= self.max_scroll:
      return
    self._scroll += val
      
  def draw(self):
    if self.state == 'scroll_right':
      self.scroll(-3)
    elif self.state == 'scroll_left':
      self.scroll(3)
      
    self.field.draw()
    glPushMatrix()
    
    glTranslatef(self.x,self.y,0)
    
    if self._scroll > 0:
      self.a_right.draw()
      
    if self._scroll < self.max_scroll:
      self.a_left.draw()
    
    set_clip_rect((10,0,self.width-10,self.height*2))
    
    glTranslatef(-self._scroll+10,0,0)
     
    self.batch.draw()
    unset_clip_rect()
    glPopMatrix()
    
  def listens(self):
    return [('events/mouse/mouse_press',self.on_press),('events/mouse/mouse_release',self.on_release)]
  
class GridBox(GridLayout):
  def __init__(self,elements):
    #scroll
    #scroll
    #layout_draw
    pass
  def mouse_press():
    pass
  def mouse_release():
    pass
    
class Editbox(Widget):
  def __init__(self,name,caption = '',pos = (0,0),size = (150,30),skin = default_skin,on_drag = None):
    Widget.__init__(self,pos,size)
    #custom params
    self.name = name
    self.caption = caption
    self.state = 'idle'
    #custom visuals
    self.svg = skin.ref('tip')
    
    self.document = pyglet.text.document.UnformattedDocument('trololo')
    self.document.set_style(0, len(self.document.text), 
        dict(color=(0, 0, 0, 255))
    )
    
    self.text1 = pyglet.text.layout.IncrementalTextLayout(
        self.document, self.width ,self.height+5, multiline=False)
    self.caret = pyglet.text.caret.Caret(self.text1)
    
    self.caption_spacev = 5
    self.caption_spaceh = 10
    self.on_text_enter = common_signals.create_channel("gui_events/on_text_entered/"+self.name)
    self.update_rect()
  
  def get_ordered_elements(self):
    return [[self.svg],[self.text1]]
  
  def update_rect(self):
    self.svg.x = self.x
    self.svg.y = self.y
    #~ self.svg.draw(self.scale)
    self.text1.x = self.x + self.caption_spacev 
    self.text1.y = self.y - self.caption_spaceh
    self.scale = ()
    #self.svg.scale = (float(self.width + self.caption_spacev * 2)/self.svg.width,float(self.height)/self.svg.height)
    
  def on_text(self,text):
    if text == '\r':
      self.on_text_enter.transmit(self.document.text)
    else:
      self.caret.on_text(text)
      
      
  def on_text_motion(self,text):
    self.caret.on_text_motion(text)
    
  
  def on_text_motion_select(self,text):
    self.caret.on_text_motion_select(text)
    
  def listens(self):
    return [('events/text/text',self.on_text),('events/text/text_motion',self.on_text_motion),('events/text/text_motion_select',self.on_text_motion_select)]

  class ButtonMenu:
    def __init__(self,buttons):
      pass
    def set_callback(self,element):
      pass

class XMLInjector:
  pass
